package graph.editor;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;

import observable.ObservableAutomaton;

import automaton.NotDeterministiTransitionException;
import automaton.NotDeterministicInitialStateException;
import automaton.State;
import automaton.Transition;
import automaton.TransitionImpl;
import automaton.UnknownInitialStateException;

@SuppressWarnings("serial")
public class GraphFrame extends JFrame {
	/**
	 * 
	 */
	GraphComponent component;
	public String[] listWord;
	private FramesController controller;

	public GraphFrame(FramesController controller) {
		this.controller = controller;

		component = new GraphComponent();
		component.setForeground(Color.BLACK);
		component.setBackground(Color.WHITE);
		component.setOpaque(true);
		component.setPreferredSize(new Dimension(800, 600));
		JScrollPane scrollPane = new JScrollPane(component);

		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		JMenu menuFile = new JMenu(GraphEditor.MENU_FILE);
		menuFile.setMnemonic('F');
		menuBar.add(menuFile);

		// ------------Adding menu item NEW -------------------
		JMenuItem itemNew = new JMenuItem(GraphEditor.MENU_ITEM_NEW);
		// set shortcut key for menu
		itemNew.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK));
		// add listener which will be called when shortcut is pressed
		itemNew.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				GraphFrame.this.controller.createFrame();
			}
		});
		menuFile.add(itemNew);

		// ------------Adding menu item SAVE -------------------
		JMenuItem itemSave = new JMenuItem(GraphEditor.MENU_ITEM_SAVE);
		// set shortcut key for menu
		itemSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK));
		// add listener which will be called when shortcut is pressed
		itemSave.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JFileChooser chooser = new JFileChooser();
				chooser.setCurrentDirectory(new java.io.File("."));
				chooser.setDialogTitle("Save Automaton");
				chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
				if (chooser.showDialog(null, "Save") == JFileChooser.APPROVE_OPTION) {
					File file = chooser.getSelectedFile();
					System.out.println(file.getPath());
					try {
						GraphComponent.saveFile(file.getPath(), component);
						JOptionPane.showMessageDialog(null, "Saving automaton success");
					} catch (Exception e2) {
						JOptionPane.showMessageDialog(null, "Saving automaton failed\n" + e2.getMessage());
					}
				}
			}
		});
		menuFile.add(itemSave);

		// ------------Adding menu item OPEN -------------------
		JMenuItem itemOpen = new JMenuItem(GraphEditor.MENU_ITEM_OPEN);
		// set shortcut key for menu
		itemOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK));
		// add listener which will be called when shortcut is pressed
		itemOpen.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JFileChooser chooser = new JFileChooser();
				chooser.setCurrentDirectory(new java.io.File("."));
				chooser.setDialogTitle("Open Automaton");
				chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
				if (chooser.showDialog(null, "Open") == JFileChooser.APPROVE_OPTION) {
					File file = chooser.getSelectedFile();
					System.out.println(file.getPath());
					try {
						GraphComponent.loadFile(file.getPath(), component);
						component.repaint();
						JOptionPane.showMessageDialog(null, "Loading automaton success");
					} catch (Exception e2) {
						JOptionPane.showMessageDialog(null, "Loading automaton failed \n" + e2.getMessage());
					}
				}
			}
		});
		menuFile.add(itemOpen);// add item to menu 'File'

		// ------------Adding menu item CLOSE -------------------
		createMenuItem(menuFile, GraphEditor.MENU_ITEM_CLOSE, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				GraphFrame.this.controller.deleteFrame(GraphFrame.this);
			}
		});

		// ------------Adding menu item QUIT -------------------
		createMenuSeparator(menuFile);
		createMenuItem(menuFile, GraphEditor.MENU_ITEM_QUIT, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				GraphFrame.this.controller.quit();
			}
		});

		JMenu menuHelp = new JMenu(GraphEditor.MENU_HELP);
		menuHelp.setMnemonic('H');
		menuBar.add(menuHelp);

		// ------------Adding menu item HELP -------------------
		createMenuItem(menuHelp, GraphEditor.MENU_ITEM_HELP, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JOptionPane.showMessageDialog(null, GraphEditor.DIALOG_HELP_MSG);
			}
		});

		// ------------Adding menu item ABOUT -------------------
		createMenuItem(menuHelp, GraphEditor.MENU_ITEM_ABOUT, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JOptionPane.showMessageDialog(null, GraphEditor.DIALOG_ABOUT_MSG);
			}
		});

		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				GraphFrame.this.controller.deleteFrame(GraphFrame.this);
			}
		});

//		JToolBar toolbar = new JToolBar();
//		toolbar.setLayout(new GridLayout(0, 1));
//		addShapeButton(toolbar, new Ellipse2D.Double(0, 0, 20, 20), "Small Circle");
//		addShapeButton(toolbar, new Ellipse2D.Double(0, 0, 40, 40), "Big Circle");
//		addShapeButton(toolbar, new Rectangle2D.Double(0, 0, 20, 20), "Small Square");
//		addShapeButton(toolbar, new Rectangle2D.Double(0, 0, 40, 40), "Big Square");

		JPanel statusPanel = new JPanel();
		statusPanel.setBorder(new BevelBorder(BevelBorder.LOWERED));
		statusPanel.setPreferredSize(new Dimension(getWidth(), 25));
		statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.X_AXIS));
		JLabel statusLabel = new JLabel("Status");
		statusLabel.setHorizontalAlignment(SwingConstants.CENTER);
		statusPanel.add(statusLabel);

		// new toolbar for automaton
		JToolBar autoToolbar = new JToolBar();
		autoToolbar.setLayout(new BoxLayout(autoToolbar, BoxLayout.LINE_AXIS));
		autoToolbar.setFloatable(false);
		// autoToolbar.add(Box.createRigidArea(new Dimension(2, 0)));

		autoToolbar.add(Box.createHorizontalGlue());
		JLabel label = new JLabel("Enter your word:");
		label.setAlignmentX(RIGHT_ALIGNMENT);
		autoToolbar.add(label);

		autoToolbar.add(Box.createRigidArea(new Dimension(2, 0)));

		final JTextField txtWord = new JTextField(20);
		txtWord.setMaximumSize(new Dimension(20, Short.MAX_VALUE));
		autoToolbar.add(txtWord);

		autoToolbar.add(Box.createRigidArea(new Dimension(2, 0)));
		// check the recognition for a given word
		addToolbarButton(autoToolbar, GraphEditor.TOOLBAR_REG, new ActionListener() {
			@SuppressWarnings("unchecked")
			public void actionPerformed(ActionEvent arg0) {
				Runnable run = new Runnable() {
					public void run() {
						int l = txtWord.getText().length();
						listWord = new String[l];
						for (int i = 0; i < l; i++) {
							listWord[i] = String.valueOf(txtWord.getText().charAt(i));
						}
						int n = component.getEdges().size();
						Transition<String>[] transitions = new Transition[n];
						for (int i = 0; i < n; i++) {
							State source = component.edges.get(i).getSource().getState();
							State target = component.edges.get(i).getDestination().getState();
							String label = component.edges.get(i).getLable();
							Transition<String> temp = new TransitionImpl<String>(source, target, label);
							transitions[i] = temp;
						}
						try {
							// DeterministicAutomaton<String> DFA = new
							// DeterministicAutomaton<String>(transitions);
							ObservableAutomaton<String> DFA = new ObservableAutomaton<String>(transitions);
							DFA.addObserver(component);
							if (listWord.length != 0) {
								if (DFA.recognize(listWord))
									JOptionPane.showMessageDialog(null, GraphEditor.DIALOG_REG_SUCCESS);
								else
									JOptionPane.showMessageDialog(null, GraphEditor.DIALOG_REG_FAIL);
							} else
								JOptionPane.showMessageDialog(null, GraphEditor.DIALOG_WORD_NULL);
						} catch (NotDeterministiTransitionException e) {
							JOptionPane.showMessageDialog(null, e.getMessage());
						} catch (NotDeterministicInitialStateException e) {
							JOptionPane.showMessageDialog(null, e.getMessage());
						} catch (UnknownInitialStateException e) {
							JOptionPane.showMessageDialog(null, e.getMessage());
						}
					}
				};

				Thread thread = new Thread(run);
				thread.start();
			}
		});

		Container contentPane = getContentPane();
//		contentPane.add(toolbar, BorderLayout.WEST);
		contentPane.add(statusPanel, BorderLayout.SOUTH);
		contentPane.add(scrollPane, BorderLayout.CENTER);
		contentPane.add(autoToolbar, BorderLayout.NORTH);
	}

//	private void addShapeButton(JToolBar toolbar, final RectangularShape sample, String name) {
//		JButton button = new JButton(name);
//		button.addActionListener(new ActionListener() {
//			public void actionPerformed(ActionEvent e) {
//				component.setVertexSample(sample);
//			}
//		});
//		toolbar.add(button);
//	}

	private void addToolbarButton(JToolBar toolbar, String name, ActionListener action) {
		JButton button = new JButton(name);
		button.addActionListener(action);
		button.setMargin(new Insets(2, 8, 2, 8));
		toolbar.add(button);
	}

	private void createMenuItem(JMenu menu, String name, ActionListener action) {
		JMenuItem menuItem = new JMenuItem(name);
		menuItem.addActionListener(action);
		menu.add(menuItem);
	}

	private void createMenuSeparator(JMenu menu) {
		JSeparator separator = new JSeparator();
		separator.setForeground(Color.lightGray);
		menu.add(separator);
	}

}
